﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Data;
using System.Windows.Markup;
using ICodeShare.UI.Converters.Common;
using ICodeShare.UI.Converters.Extensions;
using System.Globalization;

namespace ICodeShare.UI.Converters
{
    #region IValueConverter
    /// <summary>
    /// 比较字符型输入转换成Boolean值
    /// </summary>
    /// <example>
    /// 1.在xmal文件引用DateConverter类所在命名空间。
    ///   xmlns:cvts="http://schemas.extended.wpf.com/converters"
    /// 2.在xaml文件添加Resources。
    ///   <Window.Resources>
    ///   <cvts:StringCompareToBooleanConverter x:Key="cvtsStringCompareToBoolean"/>
    ///   </Window.Resources>
    /// 3.在xaml文件中指定Binding值的Converter
    ///    <CheckBox IsChecked="{Binding Text,Converter={StaticResource cvtsStringCompareToBoolean},ConverterParameter='abc',Mode=OneWay}"></CheckBox>
    /// </example>
    /// <remarks>
    /// Symbol种类：
    /// 双目比较符包括：Equal,LessThan,GreaterThan,LessThanOrEqual,GreaterThanOrEqual,NotEqual,StartWith,EndWith,Contains
    /// 三目比较符包括：Between,BetweenOrEqual
    /// 多目比较符包括：StdIn
    /// 参数parameter应该包含该一个参数或多个以分号(;)分隔的参数.
    /// 如果参数parameter只包含一个参数时，这个参数表示双目比较符的比较对象。
    /// 如果参数parameter包含两个以上参数时，第一个参数表示三目比较符的下限值，第二个字符串表示双目比较符的比较对象或三目比较符的上限值。
    /// 进行StdIn比较时，参数parameter表示一组枚举值。
    /// 如果参数parameter未声明，则总返回false.
    /// </remarks>
    [ValueConversion(typeof(object), typeof(Boolean))]
    public class StringCompareToBooleanConverter : IValueConverter
    {
        #region  Members 成员变量
        private SCompareSymbol _symbol = SCompareSymbol.Equal;
        #endregion

        #region Constructors 构造函数
        /// <summary>
        /// Initializes a new instance of the CaseConverter class.
        /// </summary>
        public StringCompareToBooleanConverter()
        {
          
        }

        /// <summary>
        /// Initializes a new instance of the CaseConverter class with the specified source and target casings.
        /// </summary>
        /// <param name="casing">
        /// The source and target casings for the converter (see <see cref="Casing"/>).
        /// </param>
        public StringCompareToBooleanConverter(SCompareSymbol symbol)
        {
            this.Symbol = symbol;
        }
        #endregion

        #region  Properties 属性
        /// <summary>
        /// 比较运算符号
        /// </summary>
        [ConstructorArgument("symbol")]
        public SCompareSymbol Symbol
        {
            get
            {
                return this._symbol;
            }

            set
            {
                value.AssertEnumMember("value", SCompareSymbol.Equal, SCompareSymbol.LessThan, SCompareSymbol.GreaterThan,
                    SCompareSymbol.LessThanOrEqual, SCompareSymbol.GreaterThanOrEqual, SCompareSymbol.NotEqual,
                    SCompareSymbol.Between, SCompareSymbol.BetweenOrEqual, SCompareSymbol.StdIn, SCompareSymbol.StartWith,SCompareSymbol.EndWith,SCompareSymbol.Contains);
                this._symbol = value;
            }
        }
        #endregion

        #region  Base Class Overrides 基类方法重写
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool result = false;
            IComparable sourceValue = (IComparable)value;
            if (sourceValue == null)
            {
                result = false;
            }
            IComparable targetValue, lowerValue;
            IEnumerable<IComparable> rangeValues;
            ParseParameter(parameter, sourceValue, culture, out lowerValue, out targetValue, out rangeValues);
            switch (Symbol)
            {
                case SCompareSymbol.Equal: { 
                    result = sourceValue.CompareTo(targetValue) == 0; 
                    break; 
                }
                case SCompareSymbol.LessThan: { 
                    result = sourceValue.CompareTo(targetValue) < 0; 
                    break; 
                }
                case SCompareSymbol.GreaterThan: { 
                    result = sourceValue.CompareTo(targetValue) > 0; 
                    break; 
                }
                case SCompareSymbol.LessThanOrEqual: { 
                    result = sourceValue.CompareTo(targetValue) <= 0; 
                    break; 
                }
                case SCompareSymbol.GreaterThanOrEqual: { 
                    result = sourceValue.CompareTo(targetValue) >= 0; 
                    break;
                }
                case SCompareSymbol.NotEqual: { 
                    result = sourceValue.CompareTo(targetValue) != 0; 
                    break; 
                }
                case SCompareSymbol.Between: {
                     result = (sourceValue.CompareTo(lowerValue)>0 && sourceValue.CompareTo(targetValue)<0); 
                    break;
                }
                case SCompareSymbol.BetweenOrEqual:
                    {
                        result = (sourceValue.CompareTo(lowerValue) >= 0 && sourceValue.CompareTo(targetValue) <= 0); 
                        break;
                    }
                case SCompareSymbol.StdIn: {
                    if (rangeValues == null)
                    {
                        result = false;
                    }
                    else
                    {
                        result = rangeValues.Contains(sourceValue);
                    }
                    break;
                }
                case SCompareSymbol.StartWith: {
                    if((value is string))
                    {
                        result = ((string)value).StartsWith(((string)targetValue), false, culture);
                    }
                    else
                    {
                        result=false;
                    }
                    break; 
                }
                case SCompareSymbol.EndWith: {
                    if ((value is string))
                    {
                        result = ((string)value).EndsWith(((string)targetValue), false, culture);
                    }
                    else
                    {
                        result = false;
                    }
                    break; 
                }
                case SCompareSymbol.Contains: {
                    if ((value is string))
                    {
                        result = ((string)value).Contains(((string)targetValue));
                    }
                    else
                    {
                        result = false;
                    }
                    break; 
                }
                default: break;
            }

            return result;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region Methods 方法
        private void ParseParameter<T>(object parameter, T value, CultureInfo culture, out IComparable lowerValue, out IComparable targetValue, out IEnumerable<IComparable> rangeValues) where T : IComparable
        {
            lowerValue = default(T);
            targetValue = default(T);
            rangeValues = null;
            var stringValue = parameter as string;
            if (string.IsNullOrWhiteSpace(stringValue))
                return;
            var stringValues = stringValue.Split(';');
            if (stringValues.Length == 0)
                return;

            if (stringValues.Length == 1)
            {
                targetValue = (IComparable)System.Convert.ChangeType(stringValues[0], value.GetType(), culture);
            }
            else if (stringValues.Length == 2)
            {
                lowerValue = (IComparable)System.Convert.ChangeType(stringValues[0], value.GetType(), culture);
                targetValue = (IComparable)System.Convert.ChangeType(stringValues[1], value.GetType(), culture);
            }
            else
            {
                rangeValues = stringValues.Select(x => (IComparable)System.Convert.ChangeType(x, value.GetType(), culture));
            }
        }
        #endregion

    }
    #endregion
}
